<!-- eslint-disable -->
<template>
	<view class="player-wrapper" :id="videoWrapperId" :parentId="id" :randomNum="randomNum"
		:change:randomNum="domVideoPlayer.randomNumChange" :viewportProps="viewportProps"
		:change:viewportProps="domVideoPlayer.viewportChange" :videoSrc="videoSrc"
		:change:videoSrc="domVideoPlayer.initVideoPlayer" :command="eventCommand"
		:change:command="domVideoPlayer.triggerCommand" :func="renderFunc" :change:func="domVideoPlayer.triggerFunc">
		<!-- 加载指示器 - 直接在模板中定义 -->
		<view class="custom-loading-overlay">
			<view class="custom-loading-spinner"></view>
		</view>
		<!-- 视频元素将由 renderjs 动态插入 -->
	</view>
</template>

<script>
	export default {
		props: {
			src: {
				type: String,
				default: ''
			},
			autoplay: {
				type: Boolean,
				default: false
			},
			loop: {
				type: Boolean,
				default: false
			},
			controls: {
				type: Boolean,
				default: false
			},
			objectFit: {
				type: String,
				default: 'contain'
			},
			muted: {
				type: Boolean,
				default: false
			},
			playbackRate: {
				type: Number,
				default: 1
			},
			isLoading: {
				type: Boolean,
				default: false
			},
			poster: {
				type: String,
				default: ''
			},
			id: {
				type: String,
				default: ''
			}
		},
		data() {
			return {
				randomNum: Math.floor(Math.random() * 100000000),
				videoSrc: '',
				eventCommand: null,
				renderFunc: {
					name: null,
					params: null
				},
				currentTime: 0,
				duration: 0,
				playing: false,
			}
		},
		computed: {

			videoWrapperId() {
				return `video-wrapper-${this.randomNum}`
			},
			viewportProps() {
				return {
					autoplay: this.autoplay,
					muted: this.muted,
					controls: this.controls,
					loop: this.loop,
					objectFit: this.objectFit,
					poster: this.poster,
					isLoading: this.isLoading,
					playbackRate: this.playbackRate
				}
			}
		},
		watch: {
			src: {
				handler(val) {
					setTimeout(() => {
						this.videoSrc = val
					}, 0)
				},
				immediate: true
			}
		},
		methods: {
			// eventEmit({ event, data }) {
			//   this.$emit(event, data)
			// },
			eventEmit({
				event,
				data
			}) {
				this.$emit(event, data); // 原有
				if (event === 'fullscreenchange' && data === false) { // 当监听到全屏退出
					this.$emit('videoDidExitFullScreen'); // 发射给 common-post
				}
			},
			setViewData({
				key,
				value
			}) {
				key && this.$set(this, key, value)
			},
			resetEventCommand() {
				this.eventCommand = null
			},
			play() {
				this.eventCommand = 'play'
			},
			pause() {
				this.eventCommand = 'pause'
			},
			resetFunc() {
				this.renderFunc = {
					name: null,
					params: null
				}
			},
			remove(params) {
				this.renderFunc = {
					name: 'removeHandler',
					params
				}
			},
			fullScreen(params) {
				this.renderFunc = {
					name: 'fullScreenHandler',
					params
				}
			},
			toSeek(sec, isDelay = false) {
				this.renderFunc = {
					name: 'toSeekHandler',
					params: {
						sec,
						isDelay
					}
				}
			}
		}
	}
</script>

<script module="domVideoPlayer" lang="renderjs">
	const PLAYER_ID = 'DOM_VIDEO_PLAYER'
	const LOADING_OVERLAY_CLASS = '.custom-loading-overlay'
	const LOADING_HIDDEN_CLASS = 'is-hidden' // 用于隐藏加载动画的类名

	export default {
		data() {
			return {
				num: '',
				videoEl: null,
				loadingEl: null,
				delayFunc: null,
				renderProps: {}
			}
		},
		computed: {
			playerId() {
				return `${PLAYER_ID}_${this.num}`
			},
			wrapperId() {
				return `video-wrapper-${this.num}`
			}
		},
		methods: {
			isApple() {
				const ua = navigator.userAgent.toLowerCase()
				return ua.indexOf('iphone') !== -1 || ua.indexOf('ipad') !== -1
			},

			_setupLoadingElement() {
				if (!this.loadingEl) {
					const playerWrapperEl = document.getElementById(this.wrapperId);
					if (playerWrapperEl) {
						this.loadingEl = playerWrapperEl.querySelector(LOADING_OVERLAY_CLASS);
					}
				}
				return this.loadingEl;
			},

			// 确保加载动画可见（如果条件满足），否则隐藏它
			_ensureLoadingState() {
				this._setupLoadingElement();
				if (this.loadingEl) {
					if (this.renderProps.isLoading && !this.isApple()) {
						this.loadingEl.classList.remove(LOADING_HIDDEN_CLASS);
					} else {
						this.loadingEl.classList.add(LOADING_HIDDEN_CLASS);
					}
				}
			},

			_hideLoading() {
				this._setupLoadingElement();
				if (this.loadingEl) {
					this.loadingEl.classList.add(LOADING_HIDDEN_CLASS);
				}
			},

			_revealVideo() {
				if (this.videoEl && !this.videoEl.classList.contains('video-visible')) {
					this.videoEl.classList.add('video-visible');
				}
			},

			async initVideoPlayer(src) {
				this.delayFunc = null
				await this.$nextTick()
				this._setupLoadingElement();

				if (!src) {
					this._hideLoading();
					if (this.videoEl) {
						this.videoEl.classList.remove('video-visible');
						this.videoEl.src = '';
					}
					return;
				}

				this._ensureLoadingState(); // 根据 props 决定加载动画初始是否移除 hidden 类

				if (this.videoEl) {
					this.videoEl.classList.remove('video-visible');
					this.videoEl.src = src
					return
				}

				const videoEl = document.createElement('video')
				this.videoEl = videoEl
				this.listenVideoEvent()

				const {
					autoplay,
					muted,
					controls,
					loop,
					playbackRate,
					objectFit,
					poster
				} = this.renderProps
				videoEl.src = src
				videoEl.autoplay = autoplay
				videoEl.controls = controls
				videoEl.loop = loop
				videoEl.muted = muted
				videoEl.playbackRate = playbackRate
				videoEl.id = this.playerId
				videoEl.setAttribute('preload', 'auto')
				videoEl.setAttribute('playsinline', true)
				videoEl.setAttribute('webkit-playsinline', true)
				videoEl.setAttribute('crossorigin', 'anonymous')
				videoEl.setAttribute('controlslist', 'nodownload')
				videoEl.setAttribute('disablePictureInPicture', true)
				videoEl.style.objectFit = objectFit
				poster && (videoEl.poster = poster)
				videoEl.style.width = '100%'
				videoEl.style.height = '100%'
				videoEl.style.position = 'relative';
				videoEl.style.zIndex = '1';

				const playerWrapper = document.getElementById(this.wrapperId)
				if (playerWrapper) {
					const loadingOverlayRef = playerWrapper.querySelector(LOADING_OVERLAY_CLASS);
					if (loadingOverlayRef) {
						playerWrapper.insertBefore(videoEl, loadingOverlayRef);
					} else {
						playerWrapper.appendChild(videoEl);
					}
				}
			},

			listenVideoEvent() {
				const playHandler = () => {
					this.$ownerInstance.callMethod('eventEmit', {
						event: 'play'
					})
					this.$ownerInstance.callMethod('setViewData', {
						key: 'playing',
						value: true
					})
					this._revealVideo();
					this._hideLoading(); // 视频开始播放，隐藏加载动画
				}
				this.videoEl.addEventListener('play', playHandler)

				const pauseHandler = () => {
					this.$ownerInstance.callMethod('eventEmit', {
						event: 'pause'
					})
					this.$ownerInstance.callMethod('setViewData', {
						key: 'playing',
						value: false
					})
				}
				this.videoEl.addEventListener('pause', pauseHandler)

				const endedHandler = () => {
					this.$ownerInstance.callMethod('eventEmit', {
						event: 'ended'
					})
					this.$ownerInstance.callMethod('resetEventCommand')
				}
				this.videoEl.addEventListener('ended', endedHandler)

				const canPlayHandler = () => {
					this.$ownerInstance.callMethod('eventEmit', {
						event: 'canplay'
					})
					this.execDelayFunc()
				}
				this.videoEl.addEventListener('canplay', canPlayHandler)

				const errorHandler = (e) => {
					// 如果出错，并且原本期望显示加载动画，则确保它仍然可见
					if (this.renderProps.isLoading && !this.isApple() && this.loadingEl) {
						this.loadingEl.classList.remove(LOADING_HIDDEN_CLASS);
					}
					this.$ownerInstance.callMethod('eventEmit', {
						event: 'error',
						data: e
					})
				}
				this.videoEl.addEventListener('error', errorHandler)

				const loadedMetadataHandler = () => {
					this.$ownerInstance.callMethod('eventEmit', {
						event: 'loadedmetadata'
					})
					const duration = this.videoEl.duration
					this.$ownerInstance.callMethod('eventEmit', {
						event: 'durationchange',
						data: duration
					})
					this.$ownerInstance.callMethod('setViewData', {
						key: 'duration',
						value: duration
					})
					if (!this.renderProps.autoplay || this.isApple()) {
						this.loadFirstFrame();
					}
				}
				this.videoEl.addEventListener('loadedmetadata', loadedMetadataHandler)

				const timeupdateHandler = (e) => {
					const currentTime = e.target.currentTime
					this.$ownerInstance.callMethod('eventEmit', {
						event: 'timeupdate',
						data: currentTime
					})
					this.$ownerInstance.callMethod('setViewData', {
						key: 'currentTime',
						value: currentTime
					})
				}
				this.videoEl.addEventListener('timeupdate', timeupdateHandler)

				const ratechangeHandler = (e) => {
					const playbackRate = e.target.playbackRate
					this.$ownerInstance.callMethod('eventEmit', {
						event: 'ratechange',
						data: playbackRate
					})
				}
				this.videoEl.addEventListener('ratechange', ratechangeHandler)

				if (this.isApple()) {
					this.videoEl.addEventListener('webkitpresentationmodechanged', () => {
						const isFullScreen = this.videoEl.webkitPresentationMode === 'fullscreen'
						this.$ownerInstance.callMethod('eventEmit', {
							event: 'fullscreenchange',
							data: isFullScreen
						})
					})
				} else {
					const fullscreenchangeHandler = () => {
						let isFullScreen = !!(document.fullscreenElement || document.webkitFullscreenElement);
						this.$ownerInstance.callMethod('eventEmit', {
							event: 'fullscreenchange',
							data: isFullScreen
						})
					}
					this.videoEl.addEventListener('fullscreenchange', fullscreenchangeHandler);
					this.videoEl.addEventListener('webkitfullscreenchange', fullscreenchangeHandler);
					document.addEventListener('fullscreenchange', fullscreenchangeHandler);
					document.addEventListener('webkitfullscreenchange', fullscreenchangeHandler);
				}
			},

			loadFirstFrame() {
				if (!this.videoEl) return;
				let {
					autoplay,
					muted
				} = this.renderProps;

				const revealAndHideLoading = () => {
					this._revealVideo();
					this._hideLoading(); // 隐藏加载动画
				};

				if (this.isApple()) {
					const playPromise = this.videoEl.play();
					if (playPromise !== undefined) {
						playPromise.then(() => {
							if (!autoplay) {
								this.videoEl.pause();
								revealAndHideLoading(); // 非自动播放时，手动调用
							}
							// 如果是 autoplay, 'play' 事件会处理 _hideLoading
						}).catch(err => {
							this._hideLoading(); // 播放失败也隐藏加载
						});
					} else {
						this.videoEl.play();
						if (!autoplay) {
							this.videoEl.pause();
							revealAndHideLoading();
						}
					}
				} else {
					if (!autoplay) {
						this.videoEl.muted = true;
						setTimeout(() => {
							const playPromise = this.videoEl.play();
							if (playPromise !== undefined) {
								playPromise.then(() => {
									setTimeout(() => {
										this.videoEl.pause();
										this.videoEl.muted = muted;
										revealAndHideLoading();
									}, 50);
								}).catch(error => {
									this.videoEl.muted = muted;
									revealAndHideLoading();
								});
							} else {
								this.videoEl.muted = muted;
								setTimeout(() => {
									this.videoEl.pause();
									revealAndHideLoading();
								}, 100);
							}
						}, 10);
					} else {
						// Autoplaying on non-Apple: 'play' event handles hiding loader.
						// Fallback if somehow loader isn't hidden:
						// this._hideLoading(); // No, playHandler will do it.
					}
				}
			},

			triggerCommand(eventType) {
				if (eventType && this.videoEl) {
					this.$ownerInstance.callMethod('resetEventCommand')
					if (typeof this.videoEl[eventType] === 'function') {
						const promise = this.videoEl[eventType]();
						if (promise && typeof promise.catch === 'function') {
							promise.catch(error => {
								/* console.warn(...) */ });
						}
					}
				}
			},
			triggerFunc(func) {
				const {
					name,
					params
				} = func || {}
				if (name && typeof this[name] === 'function') {
					this[name](params)
					this.$ownerInstance.callMethod('resetFunc')
				}
			},
			removeHandler() {
				if (this.videoEl) {
					this.videoEl.pause()
					this.videoEl.src = ''
					this.videoEl.classList.remove('video-visible');
					this.$ownerInstance.callMethod('setViewData', {
						key: 'videoSrc',
						value: ''
					})
				}
				this._hideLoading();
			},
			fullScreenHandler() {
				if (this.videoEl) {
					if (this.isApple()) {
						this.videoEl.webkitEnterFullscreen && this.videoEl.webkitEnterFullscreen()
					} else {
						if (this.videoEl.requestFullscreen) this.videoEl.requestFullscreen();
						else if (this.videoEl.webkitRequestFullscreen) this.videoEl.webkitRequestFullscreen();
						else if (this.videoEl.msRequestFullscreen) this.videoEl.msRequestFullscreen();
					}
				}
			},
			toSeekHandler({
				sec,
				isDelay
			}) {
				const func = () => {
					if (this.videoEl && sec >= 0 && sec <= this.videoEl.duration) {
						this.videoEl.currentTime = sec
					}
				}
				if (isDelay) {
					this.delayFunc = func
				} else {
					if (this.videoEl && this.videoEl.readyState >= 1) func();
					else this.delayFunc = func;
				}
			},
			execDelayFunc() {
				if (this.delayFunc && typeof this.delayFunc === 'function') {
					this.delayFunc()
					this.delayFunc = null
				}
			},
			viewportChange(newProps, oldProps) {
				this.renderProps = newProps || {};
				const {
					autoplay,
					muted,
					controls,
					loop,
					playbackRate,
					objectFit,
					poster
				} = newProps || {};

				if (this.videoEl) {
					if (!oldProps || newProps.autoplay !== oldProps.autoplay) this.videoEl.autoplay = autoplay;
					if (!oldProps || newProps.controls !== oldProps.controls) this.videoEl.controls = controls;
					if (!oldProps || newProps.loop !== oldProps.loop) this.videoEl.loop = loop;
					if (!oldProps || newProps.muted !== oldProps.muted) this.videoEl.muted = muted;
					if (!oldProps || newProps.playbackRate !== oldProps.playbackRate) this.videoEl.playbackRate =
						playbackRate;
					if (!oldProps || newProps.objectFit !== oldProps.objectFit) this.videoEl.style.objectFit = objectFit;
					if (!oldProps || newProps.poster !== oldProps.poster) this.videoEl.poster = poster;
				}

				this._ensureLoadingState(); // 根据新的 isLoading prop 更新加载动画状态
			},
			randomNumChange(val) {
				this.num = val
			}
		}
	}
</script>

<style scoped>
	.player-wrapper {
		overflow: hidden;
		width: 100%;
		height: 100%;
		padding: 0;
		position: relative;
		background-color: #000;
	}

	::v-deep .player-wrapper video {
		opacity: 0;
		transition: opacity 0.5s ease-in-out;
		display: block;
		width: 100%;
		height: 100%;
	}

	::v-deep .player-wrapper video.video-visible {
		opacity: 1;
	}

	.custom-loading-overlay {
		position: absolute;
		top: 0;
		left: 0;
		z-index: 10;
		width: 100%;
		height: 100%;
		background-color: #f8f8f8;
		display: flex;
		align-items: center;
		justify-content: center;
		opacity: 1;
		/* 初始可见 */
		pointer-events: auto;
		/* 初始可交互，阻止下方点击 */
		transition: opacity 0.3s ease-out;
		/* 淡出过渡 */
	}

	.custom-loading-overlay.is-hidden {
		/* 添加此类以隐藏加载动画 */
		opacity: 0;
		pointer-events: none;
		/* 隐藏后不可交互 */
	}

	.custom-loading-spinner {
		width: 30px;
		height: 30px;
		/* 
    主边框颜色：选择一个比 #f8f8f8 稍暗一些的灰色，以确保可见性。
    例如：#adadad (中灰色)
    轨迹颜色：选择一个比主边框更浅的灰色，或者主边框颜色的半透明版本。
    例如：#e0e0e0 (浅灰色) 或 rgba(173, 173, 173, 0.25)
  */
		border: 2px solid #adadad;
		/* Spinner 主环颜色 - 中灰色 */
		border-top-color: #e0e0e0;
		/* 轨迹颜色 - 浅灰色，让旋转效果更柔和 */
		border-right-color: #e0e0e0;
		/* 轨迹颜色 - 浅灰色 */
		border-bottom-color: #e0e0e0;
		/* 轨迹颜色 - 浅灰色 */
		border-radius: 100%;
		animation: dom-video-player-circle-spin 0.75s linear infinite;
	}

	@keyframes dom-video-player-circle-spin {
		0% {
			transform: rotate(0);
		}

		100% {
			transform: rotate(360deg);
		}
	}
</style>